package cz.muni.fi.pa165.travelagency.web;

import com.samaxes.stripes.ejb3.EJBBean;
import cz.muni.fi.pa165.travelagency.api.entities.ICustomer;
import cz.muni.fi.pa165.travelagency.api.entities.IOrder;
import cz.muni.fi.pa165.travelagency.api.entities.IPackageTour;
import cz.muni.fi.pa165.travelagency.api.entities.ITour;
import cz.muni.fi.pa165.travelagency.api.services.ICustomerService;
import cz.muni.fi.pa165.travelagency.api.services.IOrderService;
import cz.muni.fi.pa165.travelagency.api.services.IPackageTourService;
import cz.muni.fi.pa165.travelagency.api.services.ITourService;
import cz.muni.fi.pa165.travelagency.dto.CustomerDTO;
import cz.muni.fi.pa165.travelagency.dto.OrderDTO;
import cz.muni.fi.pa165.travelagency.dto.PackageTourDTO;
import cz.muni.fi.pa165.travelagency.dto.TourDTO;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.EJBs;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.Before;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.HandlesEvent;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.controller.LifecycleStage;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Implementation of action bean of order
 *
 * @author Marián Mozola
 */
@UrlBinding("/orders/{$event}/{order.id}")
@EJBs({
    @EJB(name = "orderService", beanInterface = IOrderService.class),
    @EJB(name = "customerService", beanInterface = ICustomerService.class),
    @EJB(name = "ptourService", beanInterface = IPackageTourService.class),
    @EJB(name = "tourService", beanInterface = ITourService.class)
})
public class OrderActionBean implements ActionBean {

    final static Logger log = LoggerFactory.getLogger(OrderActionBean.class);
    private ActionBeanContext context;
    @ValidateNestedProperties(value = {
        @Validate(on = {"add", "save"}, field = "numberOfPersons", required = true, minvalue = 1),
        @Validate(on = {"add", "save"}, field = "orderedPackageTour", required = true, minvalue = 1),
        @Validate(on = {"add", "save"}, field = "customer", required = true, minvalue = 1),
    })
    private OrderDTO order;
    
    @EJBBean("java:comp/env/orderService")
    @EJB(name = "orderService", beanInterface = IOrderService.class)
    private IOrderService orderService;
    
    private CustomerDTO customer;
    private PackageTourDTO orderedPackageTour;
    private List<TourDTO> orderedTours;
    private List<OrderDTO> allOrders;
    private List<OrderDTO> unpaidOrders;
    
    @EJBBean("java:comp/env/customerService")
    private ICustomerService customerService;
    @EJBBean("java:comp/env/ptourService")
    private IPackageTourService ptourService;
    @EJBBean("java:comp/env/tourService")
    private ITourService tourService;

    @Override
    public void setContext(ActionBeanContext context) {
        this.context = context;
    }

    @Override
    public ActionBeanContext getContext() {
        return context;
    }

    @DefaultHandler
    public Resolution all() {
        return new ForwardResolution("/order_show.jsp");
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"add", "save"})
    public void loadPackageTourAndCustomerFromDatabase() {
        String id = context.getRequest().getParameter("order.orderedPackageTour");
        if (id != null) {
            orderedPackageTour = (PackageTourDTO) ptourService.getPackageTour(Long.parseLong(id));
        }
        
        id = context.getRequest().getParameter("order.customer");
        if (id != null) {
            customer = (CustomerDTO) customerService.getCustomer(Long.parseLong(id));
        }        
    }
    
    @Before(stages = LifecycleStage.BindingAndValidation, on = {"delete", "edit", "choose-tours", "add-tours"})
    public void loadOrderFromDatabase() {
        String id = context.getRequest().getParameter("order.id");
        if (id == null) {
            return;
        }
        
        order = (OrderDTO) orderService.getOrder(Long.parseLong(id));
    }
    
    @Before(stages = LifecycleStage.BindingAndValidation, on = {"add-tours"})
    public void loadToursFromDatabase() {
        orderedTours = new ArrayList<>();
        String[] ids = context.getRequest().getParameterValues("tour.ids");
        if (ids == null) {
            return;
        }
        
        for (String id : ids) {
            orderedTours.add((TourDTO) tourService.getTour(Long.parseLong(id)));
        }
    }
    
    @Before(stages = LifecycleStage.BindingAndValidation, on = {"all"})
    public void loadAllOrdersFromDatabase() {
        allOrders = new ArrayList<>();
        for (IOrder io: orderService.findAll()) {
            allOrders.add((OrderDTO) io);
        }
    }

    @Before(stages = LifecycleStage.BindingAndValidation, on = {"unpaid-orders"})
    public void loadUnpaidOrdersFromDatabase() {
        unpaidOrders = new ArrayList<>();
        for (IOrder io: orderService.findUnpaid()) {
            unpaidOrders.add((OrderDTO) io);
        }
    }
    
    @Before(stages = LifecycleStage.BindingAndValidation, on = {"orders-of-customer"})
    public void loadCustomerFromDatabase() {
        String id = context.getRequest().getParameter("customer.id");
        if (id == null) {
            return;
        }
        
        customer = (CustomerDTO) customerService.getCustomer(Long.parseLong(id));
    }    

    @HandlesEvent("orders-of-customer")
    public Resolution ordersOfCustomer() {
        allOrders = new ArrayList<>();
        for (IOrder io: customer.getOrders()) {
            allOrders.add((OrderDTO) io);
        }
        return new ForwardResolution("/order_show.jsp");
    }

    public List<OrderDTO> getAllOrders() {
        return allOrders;
    }

    public List<OrderDTO> getUnpaidOrders() {
        return unpaidOrders;
    }
    
    public CustomerDTO getCustomer() {
        return (CustomerDTO) order.getCustomer();
    }

    public void setCustomer(CustomerDTO customer) {
        this.customer = customer;
    }

    public PackageTourDTO getOrderedPackageTour() {
        return (PackageTourDTO) order.getOrderedPackageTour();
    }

    public void setOrderedTours(List<TourDTO> orderedTours) {
        this.orderedTours = orderedTours;
    }

    public void setOrderedPackageTour(PackageTourDTO orderedPackageTour) {
        this.orderedPackageTour = orderedPackageTour;
    }

    public List<ITour> getOrderedTours() {
        return order.getOrderedTours();
    }

    public List<ICustomer> getAllCustomers() {
        return customerService.findAll();
    }

    public List<IPackageTour> getAllPackageTours() {
        return ptourService.findAll();
    }

    public void setOrder(OrderDTO order) {
        this.order = order;
    }

    public OrderDTO getOrder() {
        return order;
    }

    public Resolution add() {
        if(orderedPackageTour == null) {
            return new RedirectResolution(this.getClass(), "all");
        }
        
        if(customer == null) {
            return new RedirectResolution(this.getClass(), "all");
        }
        
        order.setCreated(new Date(System.currentTimeMillis()));
        order.setOrderedPackageTour(orderedPackageTour);
        BigDecimal price = orderedPackageTour.getPricePerPerson();
        price = price.multiply(BigDecimal.valueOf(order.getNumberOfPersons()));
        order.setPrice(price);
 
        order.setCustomer(customer);
        order.setOrderedPackageTour(orderedPackageTour);
        
        orderService.createOrder(order);
        return new RedirectResolution(this.getClass(), "all");
    }

    public Resolution edit() {
        return new ForwardResolution("/order_edit.jsp");
    }

    public Resolution save() {
        order.setCustomer(customer);
        order.setOrderedPackageTour(orderedPackageTour);
        orderService.updateOrder(order);
        return new RedirectResolution(this.getClass(), "all");
    }

    public Resolution cancel() {
        return new ForwardResolution(this.getClass(), "all");
    }
    
    @HandlesEvent("choose-tours")
    public Resolution choseTours() {
        return new ForwardResolution("/order_add_tour.jsp");
    }
    
    @HandlesEvent("add-tours")
    public Resolution addTour() {
        List<ITour> iOrderedTours = new ArrayList<>();
        BigDecimal toursPrice = new BigDecimal(0);
        for (TourDTO t : orderedTours) {
            if (!t.getOrders().contains(order)) {
                toursPrice = toursPrice.add(t.getPricePerPerson());
            }
            iOrderedTours.add(t);
        }
        
        order.setOrderedTours(iOrderedTours);
        toursPrice = toursPrice.multiply(BigDecimal.valueOf(order.getNumberOfPersons()));
        order.setPrice(order.getPrice().add(toursPrice));
            
        orderService.updateOrder(order);
        return new RedirectResolution(this.getClass(), "all");
    }
    
    public Resolution delete() {
        if (order != null) {
            orderService.deleteOrder(order);
        }
        
        return new RedirectResolution(this.getClass(), "all");
    }
    @HandlesEvent("unpaid-orders")
    public Resolution unpaid() {
        return new ForwardResolution("/order_show_unpaid.jsp");
    }
}
